﻿using System;
using System.Collections.Generic;
using System.Text;
using Atosenet.PluginEngine;

namespace Atosenet.Protocol
{
    [PluginAttribute("Atosenet", "Atosenet.Protocol.ProtocolPacketATPB", "ATOS工业标准协议", PluginType.Protocol)]
    public class ProtocolPacketATPB : ProtocolPacket
    {
        #region 成员

        /* 包头标志1 */
        public const byte ASP_SOP_1 = 0x37;
        public const byte ASP_SOP_2 = 0xA9;

        /* 协议包各部分长度 */
        public const int ASP_SOP_LENGTH = 2;
        public const int ASP_CMD_LENGTH = 1;
        public const int ASP_LEN_LENGTH = 2;
        public const int ASP_HCS_LENGTH = 1;
        public const int ASP_PCS_LENGTH = 1;
        public const int ASP_HEADER_LENGTH = ASP_SOP_LENGTH + ASP_CMD_LENGTH + ASP_LEN_LENGTH + ASP_HCS_LENGTH;


        private int _countHeader = 0; //当前已存包头长度
        private int _countData = 0; //当前已存数据长度

        private byte[] _bufferHeader;    //包头缓冲区
        private byte[] _bufferData;      //包内数据缓冲区

        private bool _headerOk = false;
        private bool _dataOk = false;
        private bool _pcsOk = false;

        private bool _validHeader = false;
        private bool _validData = false;
        private int _indexSop = 0;
        private int _indexCmd = 0;
        private int _indexLen = 0;
        private int _indexHcs = 0;

        private byte _pcs = 0;
        private byte _hcs = 0;
        private byte _cmd = 0;
        private UInt16 _len = 0;

        private ATPBPacketState _state = ATPBPacketState.SOP1;

        protected DateTime _receiveTime;

        #endregion


        #region 初始化

        public ProtocolPacketATPB()
        { }

        #endregion


        #region 公开函数

        public override void Append(byte[] data, ref int offset)
        {
            bool done = false;

            while (!done && offset < data.Length)
            {
                done = true;

                switch (_state)
                {
                    case ATPBPacketState.SOP1:
                        while (offset < data.Length)
                        {
                            if (data[offset++] == ASP_SOP_1)
                            {
                                _state = ATPBPacketState.SOP2;
                                done = offset >= data.Length;
                                break;
                            }
                        }
                        break;

                    case ATPBPacketState.SOP2:
                        if (data[offset++] == ASP_SOP_2)
                        {
                            CreateHeader();
                            _state = ATPBPacketState.Header;
                        }
                        else
                        {
                            _state = ATPBPacketState.SOP1;
                        }
                        done = offset >= data.Length;
                        break;

                    case ATPBPacketState.Header:
                        AppendHeader(data, ref offset);

                        if (_headerOk)
                        {
                            ParseHeader();

                            if (!_validHeader)
                            {
                                _state = ATPBPacketState.Error;
                                return;
                            }
                            CreateData();
                            _state = ATPBPacketState.Data;
                        }
                        done = offset >= data.Length;
                        break;

                    case ATPBPacketState.Data:
                        AppendData(data, ref offset);

                        if (_dataOk)
                        {
                            _state = ATPBPacketState.PCS;
                        }
                        done = offset >= data.Length;
                        break;

                    case ATPBPacketState.PCS:
                        AppendPCS(data, ref offset);

                        if (_pcsOk)
                        {
                            _state = ATPBPacketState.Completed;
                            _receiveTime = DateTime.Now;
                        }
                        break;
                }
            }
        }

        public override byte[] Generate()
        { //根据包内数据生成字节流并返回
            //此前必须设置相应的CMD，DATA的内容

            //检查LEN与DATA是否对应
            if (_bufferData == null || LEN != _bufferData.Length)
                return null;

            //数据包总长度　＝　包头长度　＋　数据长度　＋　校验码长度
            int nPacketLength = ASP_HEADER_LENGTH + LEN + ASP_PCS_LENGTH;
            int nIndex = 0;
            int nLen = 0;
            byte[] aData = new byte[nPacketLength];

            //加入包头
            GenerateHeader();
            nLen = ASP_HEADER_LENGTH;
            Array.Copy(_bufferHeader, 0, aData, nIndex, nLen);
            nIndex += nLen;

            //加入包内数据
            nLen = LEN;
            Array.Copy(_bufferData, 0, aData, nIndex, nLen);
            nIndex += nLen;

            //加入PCS            
            _pcs = CalcPCS();
            aData[nIndex] = _pcs;

            return aData;
        }

        public override void Reset()
        {
            _countHeader = 0;
            _countData = 0;
            _bufferHeader = new byte[0];
            _bufferData = new byte[0];
            _headerOk = false;
            _dataOk = false;
            _pcsOk = false;
            _validHeader = false;
            _validData = false;
            _indexSop = 0;
            _indexCmd = 0;
            _indexLen = 0;
            _indexHcs = 0;
            _pcs = 0;
            _hcs = 0;
            _cmd = 0;
            _len = 0;
            _state = ATPBPacketState.SOP1;
        }

        public override object Clone()
        {
            ProtocolPacketATPB packet = ProtocolPacketATPB.CreatePacket(this.CMD, this.DATA);
            packet._receiveTime = this.Timestamp;
            return packet;
        }

        public override string ToString()
        {
            string result = string.Format("APT-B Protocol Packet{0}([SOP]={1},[CMD]={2},[LEN]={3},[HCS]={4},[DATA]={5},[PCS]={6})",
                Environment.NewLine,
                Converter.ConvertToHexString(new byte[] { ASP_SOP_1, ASP_SOP_2 }),
                CMD.ToString("X2"),
                LEN.ToString("X2"),
                HCS.ToString("X2"),
                Converter.ConvertToHexString(DATA),
                PCS.ToString("X2"));
            return result;
        }

        #endregion


        #region 静态函数

        public static ProtocolPacketATPB CreatePacket(byte fieldCmd, byte[] fieldData)
        {
            ProtocolPacketATPB packet = new ProtocolPacketATPB();
            packet.CMD = fieldCmd;
            packet.DATA = fieldData;
            byte[] data = packet.Generate();
            return ProtocolPacketATPB.CreatePacket(data);
        }

        public static ProtocolPacketATPB CreatePacket(byte fieldCmd)
        {
            ProtocolPacketATPB packet = new ProtocolPacketATPB();
            packet.CMD = fieldCmd;
            packet.DATA = new byte[] { };
            packet.Generate();
            byte[] data = packet.Generate();
            return ProtocolPacketATPB.CreatePacket(data);
        }

        public static ProtocolPacketATPB CreatePacket(byte[] rawData)
        {
            ProtocolPacketATPB packet = new ProtocolPacketATPB();
            int offset = 0;
            packet.Append(rawData, ref offset);
            return packet;
        }

        public static ProtocolPacketATPB CreatePacket()
        {
            ProtocolPacketATPB packet = new ProtocolPacketATPB();
            return packet;
        }

        #endregion


        #region 核心函数

        private byte CalcPCS()
        {
            byte pcs = (byte)(_bufferHeader[2]); //跳过SOP，从SN的第3字节开始

            for (int i = 3; i < _bufferHeader.Length; i++)
            {
                pcs ^= (byte)(_bufferHeader[i]);
            }

            for (int i = 0; i < _bufferData.Length; i++)
            {
                pcs ^= (byte)(_bufferData[i]);
            }
            return pcs;
        }

        private byte CalcHCS()
        {
            byte hcs = _bufferHeader[2];

            for (int i = 3; i < _bufferHeader.Length - 1; i++)
            {
                hcs ^= _bufferHeader[i];
            }
            return hcs;
        }

        private void CreateHeader()
        {
            _bufferHeader = new byte[ASP_HEADER_LENGTH];
            _bufferHeader[0] = ASP_SOP_1;
            _bufferHeader[1] = ASP_SOP_2;
            _countHeader = 2;
        }

        private bool CreateData()
        {//初始化包内数据缓冲区，准备接收包内数据
            if (LEN < 0)
                return false;

            _bufferData = new byte[LEN];
            _countData = 0;
            return true;
        }

        private bool CheckPCS()
        {//检验数据库包中的FCS是否与
            return (_pcs == CalcPCS());
        }

        private bool CheckHCS()
        {
            return (_hcs == CalcHCS());
        }

        private bool ParseHeader()
        {//解析包头
            byte[] data = _bufferHeader;
            _validHeader = false;
            int nIndex = 0; //目前读取到的位置
            int nLen = 0;   //每次getData的长度

            //查找包头            
            nLen = ASP_SOP_LENGTH;
            nIndex = 0;

            if (FindSOP(data, ref nIndex) < 0)
                return false;

            _indexSop = nIndex;
            nIndex += nLen;

            //取得CMD
            nLen = ASP_CMD_LENGTH;
            _indexCmd = nIndex;
            _cmd = data[nIndex];
            nIndex += nLen;

            //取得LEN
            nLen = ASP_LEN_LENGTH;
            _indexLen = nIndex;
            _len = Converter.ConvertToUInt16BE(data, nIndex);
            nIndex += nLen;

            //取得HCS
            nLen = ASP_HCS_LENGTH;
            _indexHcs = nIndex;
            _hcs = data[nIndex];
            nIndex += nLen;

            _validHeader = CheckHCS();
            return _validHeader;
        }

        private int FindSOP(byte[] data, ref int offset)
        {
            byte[] sops = new byte[] { ASP_SOP_1, ASP_SOP_2 };
            return FindData(data, sops, ref offset);
        }

        private int FindData(byte[] data, byte[] toFind, ref int offset)
        {//在缓冲区中查找相应的数据段!!!             
            if (data == null)
                return -1;

            for (int i = 0; i < toFind.Length; )
            {
                if (offset >= data.Length)
                    return -1;

                if (data[offset++] == toFind[i])
                {
                    i++;
                    continue;
                }
                else
                {
                    i = 0;
                }
            }
            offset -= toFind.Length;
            return 1;
        }

        private bool AppendHeader(byte[] data, ref int offset)
        { //添加数据到包头
            if (_countHeader >= ASP_HEADER_LENGTH)
            {
                _headerOk = true;
                return true;
            }

            while (offset < data.Length)
            {
                _bufferHeader[_countHeader++] = data[offset++];

                if (_countHeader >= ASP_HEADER_LENGTH)
                {
                    _headerOk = true;
                    return true;
                }
            }
            return false;
        }

        private bool AppendData(byte[] data, ref int offset)
        {//增加包内数据
            if (_countData >= LEN)
            {
                _dataOk = true;
                return true;
            }

            while (offset < data.Length)
            {
                _bufferData[_countData++] = data[offset++];

                if (_countData >= LEN)
                {
                    _dataOk = true;
                    return true;
                }
            }
            return false;
        }

        private bool AppendPCS(byte[] data, ref int offset)
        {//增加检验码

            if (offset < data.Length)
            {
                _pcs = data[offset++];
                _pcsOk = true;
                return true;
            }
            return false;
        }

        private bool GenerateHeader()
        {//用SOP，SN，CMD，LEN生成对应的包头
            CreateHeader();
            int nIndex = 0;
            int nLen = ASP_CMD_LENGTH;
            byte[] aData;

            //生成SOP
            _bufferHeader[nIndex] = ASP_SOP_1;
            nIndex += 1;
            _bufferHeader[nIndex] = ASP_SOP_2;
            nIndex += 1;

            //生成CMD
            nLen = ASP_CMD_LENGTH;
            _bufferHeader[nIndex] = _cmd;
            nIndex += nLen;

            //生成LEN
            nLen = ASP_LEN_LENGTH;
            aData = Converter.ConvertToByteArrayBE(_len);
            Array.Copy(aData, 0, _bufferHeader, nIndex, nLen);
            nIndex += nLen;

            //生成HCS
            nLen = ASP_HCS_LENGTH;
            _hcs = CalcHCS();
            _bufferHeader[nIndex] = _hcs;

            return true;
        }

        #endregion


        #region 属性

        public override byte[] PacketFlag
        {
            get { return new byte[] { ASP_SOP_1, ASP_SOP_2 }; }
        }

        public override bool IsCompleted
        {
            get { return _state == ATPBPacketState.Completed; }
        }

        public override string PacketDataHex
        {
            get { return Converter.ConvertToHexString(RawData); }
        }

        public override bool IsValid
        {
            get 
            {
                if (!_headerOk || !_dataOk || !_pcsOk)
                    return false;

                _validData = CheckPCS();
                return _validHeader && _validData;
            }
        }

        public override bool HasError
        {
            get { return _state == ATPBPacketState.Error; }
        }

        public override byte[] RawData
        {
            get 
            {
                byte[] data = Generate();
                return data;
            }
        }

        public byte[] DATA
        {
            get
            {
                if (LEN == 0)
                    return new byte[0];  //返回空数据组

                return _bufferData;
            }
            set
            {
                if (value == null)
                {
                    _bufferData = null;
                }
                else
                {
                    _len = (UInt16)value.Length;
                    CreateData();
                    value.CopyTo(_bufferData, 0);
                }
            }
        }

        public byte PCS
        {
            get { return _pcs; }
        }

        public byte HCS
        {
            get { return _hcs; }
        }

        public UInt16 LEN
        {
            get { return _len; }
        }

        public byte CMD
        {
            get { return _cmd; }
            set { _cmd = value; }
        }

        public override DateTime Timestamp
        {
            get { return _receiveTime; }
        }
        
        #endregion


        #region 事件



        #endregion
    }


    internal enum ATPBPacketState
    {
        SOP1 = 0,
        SOP2 = 1,
        Header = 2,
        Data = 3,
        PCS = 4,
        Completed = 5,
        Error = 6
    }
}
